package com.enation.app.javashop.core.promotion.newcomer.service.impl;

import com.enation.app.javashop.core.base.CachePrefix;
import com.enation.app.javashop.core.goods.model.dto.BuyRecord;
import com.enation.app.javashop.core.promotion.newcomer.model.dos.NewcomerDO;
import com.enation.app.javashop.core.promotion.newcomer.model.dos.NewcomerGoodsDO;
import com.enation.app.javashop.core.promotion.newcomer.model.vos.MiniNewcomerDataVO;
import com.enation.app.javashop.core.promotion.newcomer.service.NewcomerGoodsManager;
import com.enation.app.javashop.core.promotion.tool.model.dos.PromotionGoodsDO;
import com.enation.app.javashop.core.promotion.tool.model.enums.PromotionTypeEnum;
import com.enation.app.javashop.core.promotion.tool.service.PromotionGoodsManager;
import com.enation.app.javashop.core.statistics.StatisticsException;
import com.enation.app.javashop.core.trade.order.model.enums.YesOrNoEnums;
import com.enation.app.javashop.framework.context.UserContext;
import com.enation.app.javashop.framework.database.DaoSupport;
import com.enation.app.javashop.framework.security.model.Seller;
import com.enation.app.javashop.framework.util.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import com.enation.app.javashop.core.promotion.shetuan.model.dos.ShetuanDO;
import com.enation.app.javashop.core.promotion.shetuan.service.ShetuanManager;
import com.enation.app.javashop.core.promotion.tool.model.dto.PromotionDTO;
import com.enation.app.javashop.core.promotion.tool.support.PromotionCacheKeys;
import com.enation.app.javashop.core.shop.service.ShopManager;
import com.enation.app.javashop.core.trade.cart.service.CartOriginDataManager;
import com.enation.app.javashop.framework.cache.Cache;
import com.enation.app.javashop.framework.exception.ServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;

import com.enation.app.javashop.framework.database.Page;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * @Author: zhou
 * @Date: 2021/2/25
 * @Description:
 */
@Service
public class NewcomerGoodsManagerImpl implements NewcomerGoodsManager {

    @Autowired
    @Qualifier("systemDaoSupport")
    private DaoSupport daoSupport;

    @Autowired
    private PromotionGoodsManager promotionGoodsManager;

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private ShopManager shopManager;
    @Autowired
    private ShetuanManager shetuanManager;
    @Autowired
    private Cache cache;
    @Autowired
    private CartOriginDataManager cartOriginDataManager;

    @Override
    public void addNewcomerGoods(List<NewcomerGoodsDO> newcomerGoodsDOList) {
        if (CollectionUtils.isEmpty(newcomerGoodsDOList)) {
            throw new StatisticsException("参数异常");
        }

        // 保存商品时，先删除原来的，再添加
        deleteNewcomer(newcomerGoodsDOList.get(0).getNewcomerId());

        Seller seller = UserContext.getSeller();
        for (NewcomerGoodsDO newcomerGoodsDO : newcomerGoodsDOList) {
            newcomerGoodsDO.setSellerId(seller.getSellerId());
            newcomerGoodsDO.setSellerName(seller.getSellerName());
            newcomerGoodsDO.setSalesNum(0);
            newcomerGoodsDO.setIsDelete(YesOrNoEnums.NO.getIndex());
            newcomerGoodsDO.setCreateTime(DateUtil.getDateline());
        }

        this.daoSupport.batchInsert("es_newcomer_goods", newcomerGoodsDOList);
    }

    @Override
    public List<NewcomerGoodsDO> getNewcomerGoodsList(Integer newcomerId) {
        if (newcomerId == null) {
            throw new StatisticsException("参数异常");
        }
        String sql = "select * from es_newcomer_goods where newcomer_id = ? and is_delete = ?";
        return this.daoSupport.queryForList(sql, NewcomerGoodsDO.class, newcomerId, YesOrNoEnums.NO.getIndex());
    }

    // 删除活动关联商品
    private void deleteNewcomer(Integer newcomerId) {
        String deleteGoodsSql = "update es_newcomer_goods set is_delete = ? where newcomer_id = ?";
        this.daoSupport.execute(deleteGoodsSql, YesOrNoEnums.YES.getIndex(), newcomerId);

        promotionGoodsManager.deleteByActivityIds(Arrays.asList(newcomerId), PromotionTypeEnum.NEWCOMER);
    }
     /**
     * 查询今日新人购活动中的商品
     */
    @Override
    public Map<String,Object> selNewcomerGoods(Integer pageNo, Integer pageSize,String city) {
        Map<String,Object> resultMap = new HashMap<>();
        Integer sellerId = shopManager.getShopByCity(city);
        String sql = "select cg.*,c.limit_num as newcomer_limit_num,c.start_time,c.end_time,g.selling,g.thumbnail " +
                " from es_newcomer_goods cg left join es_newcomer c on cg.newcomer_id = c.newcomer_id " +
                " left join es_goods g on cg.goods_id = g.goods_id " +
                " where c.`status` = 2 and c.is_delete = 0 and cg.is_delete = 0 and c.seller_id = ?  and c.start_time <= ? and c.end_time > ?  ORDER BY c.create_time DESC ";
        List<Object> termList = new ArrayList<>();
        long newDate = DateUtil.getDateline();
        termList.add(sellerId);
        termList.add(newDate);
        termList.add(newDate);
        Page<MiniNewcomerDataVO> page = daoSupport.queryForPage(sql.toString(), pageNo, pageSize, MiniNewcomerDataVO.class, termList.toArray());
        List<MiniNewcomerDataVO> miniNewcomerDataVOList = page.getData();
        if(CollectionUtils.isEmpty(miniNewcomerDataVOList)){
            resultMap.put("newcomer_limit_num",0);
            resultMap.put("count_down",null);
            resultMap.put("buy_record_list",new ArrayList<>());
            resultMap.put("list_data",new Page());
            return resultMap;
        }
        // 查询提货时间
        List<ShetuanDO> shetuanDOList = shetuanManager.getShetuanIdBySellerId(sellerId);

        // 查询购物车
        Map<Integer, Integer> cartNumMap = cartOriginDataManager.getUserCart();

        List<BuyRecord> buyRecords =new ArrayList<>();
        // 处理数据
        for (MiniNewcomerDataVO miniNewcomerDataVO : miniNewcomerDataVOList) {
            Long pickTimeShow = CollectionUtils.isEmpty(shetuanDOList) ?  null : shetuanDOList.get(0).getPickTime();
            miniNewcomerDataVO.setPickTimeShow(pickTimeShow);
            Integer soldQuantity = miniNewcomerDataVO.getSoldQuantity() == null ? 0 : miniNewcomerDataVO.getSoldQuantity();
            Integer salesNum = miniNewcomerDataVO.getSalesNum() == null ? 0 : miniNewcomerDataVO.getSalesNum();
            Integer surplusNum = soldQuantity == null || soldQuantity == null ? 0 : soldQuantity - salesNum;
            miniNewcomerDataVO.setSurplusNum(surplusNum);

            boolean salesEnable = salesNum !=0 && salesNum>= soldQuantity ? true : false;
            miniNewcomerDataVO.setSalesEnable(salesEnable);
            // 购物车新人购 商品数量
            Integer cartNum = cartNumMap.get(miniNewcomerDataVO.getSkuId());
            miniNewcomerDataVO.setCartNum(cartNum == null ? 0 : cartNum);

            List<BuyRecord> buyRecordList = cache.range(CachePrefix.BUY_REC.getPrefix() + miniNewcomerDataVO.getSkuId(), 0, salesNum - 1);
            if(!CollectionUtils.isEmpty(buyRecordList)){
                buyRecords.addAll(buyRecordList);
            }

        }
        //活动结束时间倒计时
        Long endTime = miniNewcomerDataVOList. get(0).getEndTime();
        Integer newcomerLimitNum = miniNewcomerDataVOList.get(0).getNewcomerLimitNum();
        resultMap.put("newcomer_limit_num",newcomerLimitNum);
        resultMap.put("count_down",endTime-newDate);

        // 取前三个头像
        List<BuyRecord> buyRecordList =new ArrayList<>();
        if(!CollectionUtils.isEmpty(buyRecords)){
            int size = buyRecords.size() > 3 ? 2 : buyRecords.size();
            for (int i = 0; i < size; i++) {
                buyRecordList.add(buyRecords.get(i));
            }
        }
        resultMap.put("buy_record_list",buyRecordList);
        resultMap.put("list_data",page);
        return resultMap;
    }

    @Override
    @Transactional(value = "tradeTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = {RuntimeException.class, ServiceException.class})
    public boolean addSalesNum(List<PromotionDTO> promotionDTOList) {
        List<MiniNewcomerDataVO> lockedList = new ArrayList<>();

        boolean result = true;

        for (PromotionDTO promotionDTO : promotionDTOList) {
            try {
                //用户购买的数量
                int num = promotionDTO.getNum();

                String sql = "update es_newcomer_goods set sales_num = sales_num + ? where sku_id = ? and id = ? and (sold_quantity - sales_num) >= ?";
                logger.debug("购买数量" + num + ";商品id: " + promotionDTO.getGoodsId() + " ; 新人购主键: " + promotionDTO.getActId());
                int rowNum = this.daoSupport.execute(sql, num, promotionDTO.getProductId(), promotionDTO.getActId(),num);

                //库存不足
                if (rowNum <= 0) {
                    logger.debug("新人购已售数量更新失败");
                    result = false;
                    break;
                } else {
                    result = true;
                    MiniNewcomerDataVO miniNewcomerDataVO = new MiniNewcomerDataVO();
                    miniNewcomerDataVO.setSalesNum(num);
                    miniNewcomerDataVO.setSkuId(promotionDTO.getProductId());
                    miniNewcomerDataVO.setId(promotionDTO.getActId());
                    miniNewcomerDataVO.setGoodsId(promotionDTO.getGoodsId());

                    //记录此商品已经锁成功,以便回滚
                    lockedList.add(miniNewcomerDataVO);
                    logger.debug("新人购已售数量更新成功");
                }

                //发生锁库失败，则break;
                if (!result) {
                    break;
                }
                this.cache.remove(getRedisKey(getNewcomerById(promotionDTOList.get(0).getActId())));

            } catch (Exception e) {
                e.printStackTrace();
                result = false;
            }
        }

        //如果有锁库失败，则回滚已经更新成功的
        if (!result) {
            innerRollbackStock(lockedList);
        }
        return result;
    }

    @Override
    @Transactional(value = "tradeTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = {RuntimeException.class, ServiceException.class})
    public void rollbackStock(List<PromotionDTO> promotionDTOList) {

        List<MiniNewcomerDataVO> lockedList = new ArrayList<>();

        //遍历活动与商品关系的类
        for (PromotionDTO promotionDTO : promotionDTOList) {
            MiniNewcomerDataVO miniNewcomerDataVO = new MiniNewcomerDataVO();
            //用户购买的数量
            int num = promotionDTO.getNum();
            miniNewcomerDataVO.setSalesNum(num);
            miniNewcomerDataVO.setSkuId(promotionDTO.getProductId());
            miniNewcomerDataVO.setId(promotionDTO.getActId());
            miniNewcomerDataVO.setGoodsId(promotionDTO.getGoodsId());
            lockedList.add(miniNewcomerDataVO);

        }
        if (CollectionUtils.isEmpty(lockedList)) {
            return;
        }

        innerRollbackStock(lockedList);

        // 更新缓存
        this.cache.remove(getRedisKey(getNewcomerById(promotionDTOList.get(0).getActId())));

    }

    @Override
    public NewcomerGoodsDO getModel(Integer id){
        return daoSupport.queryForObject(NewcomerGoodsDO.class, id);
    }

    @Override
    public MiniNewcomerDataVO getNewcomerGoodsByNewcomerId(Integer newcomerId,Integer skuId) {
        String sql = "SELECT * from es_newcomer_goods cg LEFT JOIN es_newcomer c on cg.newcomer_id = c.newcomer_id where cg.newcomer_id=? and cg.sku_id=? ";
        MiniNewcomerDataVO miniNewcomerDataVO = daoSupport.queryForObject(sql, MiniNewcomerDataVO.class, newcomerId, skuId);


        List<ShetuanDO> shetuanDOList = shetuanManager.getShetuanIdBySellerId(miniNewcomerDataVO.getSellerId());
        // 送货时间
        Long pickTimeShow = CollectionUtils.isEmpty(shetuanDOList) ?  null : shetuanDOList.get(0).getPickTime();
        miniNewcomerDataVO.setPickTimeShow(pickTimeShow);

        // 剩余数量
        Integer soldQuantity = miniNewcomerDataVO.getSoldQuantity() == null ? 0 : miniNewcomerDataVO.getSoldQuantity();
        Integer salesNum = miniNewcomerDataVO.getSalesNum() == null ? 0 : miniNewcomerDataVO.getSalesNum();
        Integer surplusNum = soldQuantity == null || soldQuantity == null ? 0 : soldQuantity - salesNum;
        miniNewcomerDataVO.setSurplusNum(surplusNum);

        // 是否可销售
        boolean salesEnable = salesNum !=0 && salesNum>= soldQuantity ? true : false;
        miniNewcomerDataVO.setSalesEnable(salesEnable);
        // 当前商品 购物车新人购 商品数量
        Map<Integer, Integer> cartNumMap = cartOriginDataManager.getUserCart();
        Integer cartNum = cartNumMap.get(miniNewcomerDataVO.getSkuId());
        miniNewcomerDataVO.setCartNum(cartNum == null ? 0 : cartNum);

        // 距离活动结束时间
        miniNewcomerDataVO.setCountDown(miniNewcomerDataVO.getEndTime()-DateUtil.getDateline());

        return miniNewcomerDataVO;
    }

    /**
     * 回滚新人购库存
     */
    private void innerRollbackStock(List<MiniNewcomerDataVO> goodsList) {
        for (MiniNewcomerDataVO miniNewcomerDataVO : goodsList) {
            int salesNum = miniNewcomerDataVO.getSalesNum();
            String sql = "update es_newcomer_goods set sales_num = sales_num - ? where sku_id =? and id =? ";
            this.daoSupport.execute(sql, salesNum,  miniNewcomerDataVO.getSkuId(), miniNewcomerDataVO.getId());
        }

    }

    /**
     * 查询商品对应的活动id
     */
    private Integer  getNewcomerById(Integer id) {
        String sql = "SELECT newcomer_id from es_newcomer_goods where id = ? ORDER BY create_time ";
        return this.daoSupport.queryForInt(sql,id);
    }

    /**
     * 获取xinrenkey
     * @return
     */
    private String getRedisKey(Integer id) {
        return  getRedisKey(com.enation.app.javashop.framework.util.DateUtil.getDateline(),id);
    }
    private String getRedisKey(long time, Integer id) {
        id = id == null ? 0 : id;
        return PromotionCacheKeys.getNewcomerKey(com.enation.app.javashop.framework.util.DateUtil.toString(time, "yyyyMMdd") + "_" + id);
    }
}
